<?php

/**
 *一个简单的模板引擎
 */
class Template
{
    private $arrayConfig;

    public $file;
    private $value = array();
    private $compileTool;
    static private $instance = null;
    public $debug = array();
    private $controlData = array();

    public function __construct()
    {
        $this->arrayConfig= require(dirname(__DIR__).'/configs/template.php');
        $this->debug['begin'] = microtime(true);
        $this->getPath();

        if (!is_dir($this->arrayConfig['templatedir'])) {
            exit('template dir is not found');
        }
        if (!is_dir($this->arrayConfig['compiledir'])) {
            mkdir($this->arrayConfig['compiledir'], 0770, true);
        }
        if (!is_dir($this->arrayConfig['cachedir'])) {
            mkdir($this->arrayConfig['cachedir'], 0770, true);
        }
        include('Compile.class.php');
    }

    /**
     * 路径处理为绝对路径
     */
    public function getPath()
    {
        $this->arrayConfig['templatedir'] = strtr(realpath($this->arrayConfig['templatedir']), '\\', '/') . '/';
        $this->arrayConfig['compiledir'] = strtr(realpath($this->arrayConfig['compiledir']), '\\', '/') . '/';
        $this->arrayConfig['cachedir'] = strtr(realpath($this->arrayConfig['cachedir']), '\\', '/') . '/';
    }

    /**
     * 取得模板引擎的实例
     * @return object
     * @access public
     * @static
     */
    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new Template();
        }
        return self::$instance;
    }

    /**
     * 设置模板引擎的参数
     * @param $key
     * @param null $value
     */
    public function setConfig($key, $value = null)
    {
        if (is_array($key)) {
            $this->arrayConfig = $key + $this->arrayConfig;
        } else {
            $this->arrayConfig[$key] = $value;
        }
    }

    /**
     * 获取当前模板引擎实例的配置，仅供调试信息时使用
     * @param null $key
     * @return array
     */
    public function getConfig($key = null)
    {
        if ($key) {
            return $this->arrayConfig[$key];
        } else {
            return $this->arrayConfig;
        }
    }

    /**
     * 注入单个变量
     * @param string $key 模板变量名
     * @param mixed $value 模板变量值
     * @return void
     */
    public function assign($key, $value)
    {
        $this->value[$key] = $value;
    }

    /**
     * 注入数组变量
     * @param array $array
     */
    public function assignArray($array)
    {
        if (is_array($array)) {
            foreach ($array as $key => $value) {
                $this->value[$key] = $value;
            }
        }
    }

    /*
     * 文件完整路径
     */
    public function path()
    {
        return $this->arrayConfig['templatedir'] . $this->file . $this->arrayConfig['suffix_template'];
    }

    /**
     * 判断是否开启了缓存
     */
    public function needCache()
    {
        return $this->arrayConfig['cachehtml'];
    }

    /**
     * 是否需要重新生成静态文件
     * @param $file
     * @return bool
     */
    public function reCache($file)
    {
        $cachefile = $this->arrayConfig['compiledir'] . md5($file) . $this->arrayConfig['suffix_cache'];
        if ($this->arrayConfig['cachehtml'] === true) {//是否有缓存配置
            $timeflag = (time() - @filemtime($cachefile)) < $this->arrayConfig['cachetime'] ? true : false;
            if (is_file($cachefile) && filesize($cachefile) > 1 && $timeflag) {//缓存文件存在未过期
                return true;
            }
        }
        return false;
    }

    /**
     * 显示模板
     * @param $file
     */
    public function show($file)//判断是否允许缓存，若是，判断缓存文件是否存在且不过期。。。若是，则直接读取，若不是再判断是否重新编译(编译文件存在且不过期）
    {
        $this->file = $file;
        if (!is_file($this->path())) {//$this->path（）获取$this->file的完整路径
            echo $this->path();
            exit('template file is not found');
        }
        $compilefile = $this->arrayConfig['compiledir'] . md5($file) . $this->arrayConfig['suffix_compile'];
        $cachefile = $this->arrayConfig['compiledir'] . md5($file) . $this->arrayConfig['suffix_cache'];

        if ($this->reCache($file) === false) {
            $this->debug['cache'] = 'false';
            $this->compileTool = new CompileClass($this->path(), $compilefile, $this->arrayConfig);
            if ($this->needCache()) {
                ob_start();//开始捕获输出缓冲
            }
            extract($this->value, EXTR_OVERWRITE);
            if (!is_file($compilefile) || filemtime($compilefile) < filemtime($this->path())) {//编译文件不存在或已经过期
                //重新编译
                $this->compileTool->value = $this->value;
                $this->compileTool->compile();

                include($compilefile);
            } else {
                include($compilefile);
            }

            if ($this->needCache()) {
                $message = ob_get_contents();//获取输出缓冲(从ob_start()到ob_get_contents()之间输出）
                file_put_contents($cachefile, $message);//写入缓存
            }
        } else {
            readfile($cachefile);//读入一个文件并写入到输出缓冲。
            $this->debug['cache'] = 'true';
        }
        $this->debug['spend'] = microtime(true) - $this->debug['begin'];
        $this->debug['count'] = count($this->value);
        $this->debugInfo();
    }

    /**
     * 返回编译信息
     */
    public function debugInfo()
    {
        if ($this->arrayConfig['debug'] === true) {
            echo "<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>";
            $info = '<br/>' . '---------- debug info ----------' . '<br/>' ;
            $info .= '程序运行日期：' . date('Y-m-d H:i:s') . '<br/>' ;
            $info .= '模板解析耗时：' . $this->debug['spend'] . '秒' . '<br/>' ;
            $info .= '模板包含标签数目' . $this->debug['count'] . '<br/>' ;
            $info .= '是否使用静态缓存' . $this->debug['cache'] . '<br/>' ;
            $info .= '模板引擎实例参数';
            echo $info;
            var_dump($this->getConfig());
        }
    }

    /**
     * 清理缓存的HTML文件
     * @param numm $path
     */
    public function clean($path = null)
    {
        if ($path === null) {
            $path = $this->arrayConfig['cachedir'];
            $path = glob($path . '* ' . $this->arrayConfig['suffix_cache']);
        } else {
            $path = $this->arrayConfig['cachedir'] . md5($path) . $this->arrayConfig['suffix_cache'];
        }
        foreach ($path as $file) {
            unlink($file);  //删除文件
        }
    }
}